前端程式設計筆記 (2026.4)

HTML / CSS / JS / AJAX / Python Flask 職訓課程筆記彙整&快速工具

GARY-KAO

第十四章:綜合應用

1. 旅館清單 + 連動搜尋列實戰

這份檔案 (20260317-javascipt-ex02-hostlist.html) 是一個非常經典且完整的「前端資料處理與動態渲染」實戰範例。它完美結合了 Bootstrap 框架的排版、jQuery 的 AJAX 非同步請求,以及現代 JavaScript (ES6) 的進階陣列與字串處理技巧。

以下按照程式碼運作與建置的先後順序,為您拆解其中運用的核心語法與技巧:

步驟一:UI 架構建立與狀態預設 (HTML + Bootstrap)

在畫面呈現上,運用了 Bootstrap 的網格系統與表單元件來建構基礎骨架。

  • 網格系統 (Grid System): 使用 rowcol-md-6 將兩個下拉選單(縣市、鄉鎮區)並排,下方使用 col-md-10 放置顯示結果的表格。
  • 表單預設狀態控制: 在縣市與鄉鎮區的 <option> 中加上 selected disabled,製作出無法被當作有效值送出的「提示用選項」(例如:選擇縣市)。
  • 關鍵防呆邏輯: 鄉鎮區的 <select> 標籤預設加上了 disabled 屬性。在使用者尚未選擇「縣市」之前,強制鎖定「鄉鎮區」避免錯誤操作。

步驟二:非同步獲取外部資料 (AJAX GET)

網頁載入完成 ($(function() {...})) 後,程式立刻發起兩支獨立的 AJAX 請求來索取 JSON 資料,並儲存至全域變數中供後續使用。

  • $.ajax() 請求: 設定 type: "GET" 分別讀取 CityCountyData.json(縣市區域資料)與 HotelList.json(旅館資料)。
  • 預先渲染第一層選單: 在成功取得 CityCountyData 後,立刻使用 forEach 迴圈搭配 HTML 字串拼接,將「縣市」的選項填入第一個下拉選單 (#city) 中。

步驟三:資料清洗與正規化 (Data Normalization)

這是此範例中含金量最高的段落。從外部 API 抓回來的 HotelList 旅館資料可能存在各種瑕疵(例如欄位空缺、格式不一),程式透過自訂的 normalize(data) 函式進行了嚴格的資料清洗。

  • 陣列映射 map() 針對傳入的原始陣列,遍歷每一筆資料並回傳一個「重新格式化後」的全新陣列。
  • 空值合併運算子 ?? (Nullish Coalescing): 例如 (item.HotelName ?? "")。這用來攔截 nullundefined 的無效資料,如果遇到空值,就強制替換成空字串 "",避免後續處理(如 trim)時程式崩潰。
  • 字串去空白 .trim() 將字串前後多餘的空白鍵消除,確保資料乾淨。
  • 三元運算子 條件 ? 成立 : 不成立 例如 name === "" ? "未提供名稱" : name。進行最終防呆,如果清洗完發現字串是空的,就補上「未提供名稱」的預設文字,確保畫面上不會出現空白的破圖感。

步驟四:連動下拉式選單實作 (Event Listener & Filter)

透過監聽選單的變動,達成「選了 A 縣市,才出現 A 縣市的 B 鄉鎮」的連動效果。

  • 變更事件監聽 change() 分別監聽 #city#town 的選取動作。
  • 陣列過濾 filter()
    • 當選擇縣市時: 使用 .filter() 從全台資料中精準篩選出該縣市的 AreaList(鄉鎮區清單),接著使用 .empty() 清空舊的鄉鎮區選單,再用 forEach 填入新的鄉鎮區選項。
    • 解除鎖定: 透過 $("#town").prop("disabled", false); 將原本鎖定的第二層選單打開。
    • 當選擇鄉鎮區時: 再次使用 .filter(),透過「縣市等於所選縣市 鄉鎮等於所選鄉鎮」的雙重條件 (item.City === selected_city && item.Town === selected_town),從清洗好的旅館總表中篩選出最終結果。

步驟五:動態畫面渲染 (DOM Manipulation)

取得篩選後的最終旅館名單後,呼叫 renderTable(result) 將資料畫到網頁上。

  • 重置容器 .empty() 每次重新渲染前,必須先清空 #hostlist 內舊有的 <tr> 節點。
  • 樣板字面值 (Template Literals): 使用反引號 ` 輕鬆處理多行 HTML 字串,並透過 ${item.Name} 將 JavaScript 變數無縫嵌入 HTML 結構中。
  • 插入節點 .append() 將組合好的每一列 HTML 字串,逐一塞入表格的 <tbody> 中,完成最終的視覺呈現。

2. 進階實戰:多重條件篩選與分頁系統 (Pagination)

這份檔案 (20260317-javascipt-ex03-hostlist-filter.html) 是前一個連動選單範例的升級版。核心亮點在於加入了「關鍵字搜尋」、將表格改為「卡片佈局」,並且實作了純前端的「分頁功能」。

以下是建置這個進階系統的核心步驟與語法解析:

步驟一:進階資料清洗與鏈式寫法 (Chaining)

在原本的 normalize() 函式中,除了補齊預設文字,還新增了圖片的過濾與安全取值機制。

步驟二:多重條件篩選中心 (Apply Filter)

這是一個非常經典的過濾器設計,將「縣市」、「鄉鎮」、「關鍵字」三個條件綜合判斷,決定該筆資料去留。

步驟三:分頁邏輯實作 (Pagination Core)

純前端的分頁不依賴伺服器,而是利用陣列切割技術來達成。

步驟四:陣列切割與畫面渲染 (Slice & Render)

決定好頁碼後,要把龐大的過濾資料「切」出目前該顯示的那一塊。

步驟五:卡片排版與字串截斷 (Card UI & Substring)


3. SPA-Single Page Application

這份 Single Page Application (SPA) 專案實戰範例整合了前端三大核心與第三方套件。以下為您將建置步驟與核心邏輯(包含註冊登入模組及 AJAX 深度解析)合併整理成的完整實作流程:

步驟一:基礎環境與外部資源掛載 (Environment Setup)

在網頁的 <head><body> 底部,引入多項外部資源來建構網頁基礎:

步驟二:自訂全域樣式與視覺輔助 (Custom CSS)

在 HTML 開發前,先在 <style> 中定義高頻率使用的共用樣式:

步驟三:網頁區塊切版與元件套用 (UI Construction)

運用 Bootstrap 網格與元件,依序建構各個網頁區塊:

📌 深度解析:註冊與登入模組 (Bootstrap Modal)
這兩個模組獨立存在於 HTML 中 (#registerModal#loginModal),透過屬性綁定達成流暢切換:
  • 觸發機制:導覽列右側按鈕透過 data-bs-toggle="modal"data-bs-target 直接綁定了對應的 Modal,無需撰寫額外的 JS。
  • 二欄式排版:註冊視窗為了同時呈現「服務條款」與「註冊表單」,使用了 modal-xl(超大視窗)。內部 modal-body 透過 rowcol-6 將畫面完美切割為左右兩半。
  • 無縫視窗切換邏輯:在視窗底部 (如「已有帳號!」連結) 加入了 <a href="#" data-bs-toggle="modal" data-bs-target="#loginModal">。當使用者點擊時,Bootstrap 會自動關閉當前視窗並無縫銜接開啟新視窗。
  • 視覺引導:註冊視窗標題使用 text-bg-warning(警告黃),登入視窗使用 text-bg-success(成功綠),幫助使用者快速區分目前的作業狀態。

步驟四:動態特效與滾動監聽 (Scroll Animations)

透過 JavaScript 賦予網頁生命力與互動感:

步驟五:AJAX 非同步資料串接 (Data Fetching & Rendering)

團隊主持人介紹區塊 (#s08) 並非寫死,而是動態向第三方 API 索取資料的標準實作流程:


4. OSM 開放街圖與叢集標記實戰 (Leaflet + MarkerCluster)

本實戰展示如何使用開源的 OpenStreetMap (OSM) 搭配 Leaflet.js 繪製互動式地圖,並利用 MarkerCluster 解決大量圖標重疊問題。

步驟一:環境建置與自訂叢集樣式 (Environment & CSS)

載入 Leaflet 與 MarkerCluster 的 CSS/JS 檔案,並為地圖準備一個具有明確高度的容器。

步驟二:初始化 Leaflet 地圖與圖層 (Map Initialization)

網頁載入後,先設定中心點並準備好「叢集圖層」。

步驟三:使用 Axios 獲取資料 (Data Fetching)

捨棄 jQuery $.ajax,改用現代化的 Axios 套件來讀取包含旅館資訊的 JSON 資料。

axios.get('js/json/HotelList.json')
    .then(function (response) {
        // 成功取得資料後,將 response.data 丟入資料清洗函數
        HotelList = normalize(response.data.Hotels);
        // ...執行步驟五
    })
    .catch(function (error) {
        console.log("讀取失敗:", error);
    });
💡 Axios 與 jQuery AJAX 的差異:
Axios 採用 Promise 架構,語法更簡潔且易於處理鏈式反應,且會自動將回傳的 JSON 字串解析為 JavaScript 物件(放在 response.data 中)。

步驟四:資料清洗與座標過濾 (Data Normalization)

這是地圖成功的關鍵。必須確保每一筆要渲染的資料都具有正確的「經緯度」,避免地圖報錯當機。

步驟五:產生標記並加入叢集 (Clustering & Rendering)

最後利用 forEach 遍歷清洗後的資料,將標記 (Marker) 畫在地圖上,並綁定氣泡視窗。


5. 視覺與開發好用資源匯整

在開發專案時,善用以下資源可大幅強化 UI/UX 體驗: